package com.rc.web.service.impl;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.rc.web.utils.VivoAuth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
public class AsrVcnService {

    // 日志记录器
    private static final Logger logger = LoggerFactory.getLogger(AsrVcnService.class);
    // HTTP请求客户端
    private final RestTemplate restTemplate = new RestTemplate();
    // JSON处理工具
    private final ObjectMapper objectMapper = new ObjectMapper();
    // Vivo AI API域名
    private final String domain = "api-ai.vivo.com.cn";
    // 应用凭证
    private static final String APP_ID = "2025985389";
    private static final String APP_KEY = "eAkRKtYXOawsmtVv";

    /**
     * 生成请求ID
     * 格式：UUID-时间戳
     * @return 生成的请求ID字符串
     */
    private String generateRequestId() {
        return UUID.randomUUID().toString() + "-" + System.currentTimeMillis();
    }

    /**
     * 创建音色复刻任务
     * @param appId 应用ID
     * @param appKey 应用密钥
     * @param wavBuffer 音频文件二进制数据
     * @param text 音频对应的文本内容
     * @return 任务创建响应结果
     * @throws Exception 请求异常
     */
    private Map<String, Object> createVcnTask(String appId, String appKey, byte[] wavBuffer, String text) throws Exception {
        String uri = "/replica/create_vcn_task";
        String requestId = generateRequestId();
        String queryParams = "req_id=" + requestId;

        // 构建multipart表单数据
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("audio", new ByteArrayResource(wavBuffer) {
            @Override
            public String getFilename() {
                return "audio";
            }
        });
        body.add("text", text);

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        // 添加Vivo认证头
        headers.addAll(VivoAuth.generateAuthHeaders(appId, appKey, "POST", uri, queryParams));

        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);

        String url = "https://" + domain + uri + "?req_id=" + requestId;

        try {
            // 发送POST请求
            ResponseEntity<String> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    requestEntity,
                    String.class
            );

            // 解析响应JSON
            return objectMapper.readValue(response.getBody(), Map.class);
        } catch (Exception e) {
            logger.error("创建音色复刻任务失败", e);
            return null;
        }
    }

    /**
     * 获取音色复刻任务状态
     * @param appId 应用ID
     * @param appKey 应用密钥
     * @param vcn 音色复刻任务ID
     * @return 任务状态响应结果
     * @throws Exception 请求异常
     */
    private Map<String, Object> getVcnTask(String appId, String appKey, String vcn) throws Exception {
        String uri = "/replica/get_vcn_task";
        String requestId = generateRequestId();
        String queryParams = "req_id=" + requestId;

        // 构建请求体
        Map<String, String> body = new HashMap<>();
        body.put("vcn", vcn);

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 添加Vivo认证头
        headers.addAll(VivoAuth.generateAuthHeaders(appId, appKey, "POST", uri, queryParams));

        HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(body, headers);

        String url = "https://" + domain + uri + "?req_id=" + requestId;

        try {
            // 发送POST请求
            ResponseEntity<String> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    requestEntity,
                    String.class
            );

            // 解析响应JSON
            Map<String, Object> result = objectMapper.readValue(response.getBody(), Map.class);

            // 检查任务状态
            if (result != null && result.containsKey("vcn_obj")) {
                Map<String, Object> vcnObj = (Map<String, Object>) result.get("vcn_obj");
                if (vcnObj.containsKey("status") && (int)vcnObj.get("status") >= 3) {
                    // 任务完成，获取音频URL
                    String audioUrl = (String) vcnObj.get("audio_url");
                    if (audioUrl != null && !audioUrl.isEmpty()) {
                        // 下载并保存音频文件
                        saveAudioFile(audioUrl, vcn);
                    }
                }
            }

            return result;
        } catch (Exception e) {
            logger.error("获取音色复刻任务状态失败", e);
            return null;
        }
    }

    /**
     * 下载并保存音频文件
     * @param audioUrl 音频文件URL
     * @param vcn 任务ID
     * @throws IOException 文件操作异常
     */
    private void saveAudioFile(String audioUrl, String vcn) throws IOException {
        // 构建保存路径
        String fileName = "vcn_" + vcn + "_" + System.currentTimeMillis() + ".wav";
        Path savePath = Paths.get(System.getProperty("user.dir"), fileName);

        logger.info("开始下载音频文件: {}", audioUrl);
        logger.info("保存路径: {}", savePath);

        try (InputStream in = new URL(audioUrl).openStream();
             FileOutputStream out = new FileOutputStream(savePath.toFile())) {

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }

            logger.info("音频文件下载完成，大小: {} bytes", Files.size(savePath));
        }
    }

    /**
     * 获取所有音色复刻任务列表
     * @param appId 应用ID
     * @param appKey 应用密钥
     * @return 任务列表响应结果
     * @throws Exception 请求异常
     */
    private Map<String, Object> getVcnTaskList(String appId, String appKey) throws Exception {
        String uri = "/replica/get_vcn_task_list";
        String requestId = generateRequestId();
        String queryParams = "req_id=" + requestId;

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        // 添加Vivo认证头
        headers.addAll(VivoAuth.generateAuthHeaders(appId, appKey, "POST", uri, queryParams));

        HttpEntity<String> requestEntity = new HttpEntity<>(headers);

        String url = "https://" + domain + uri + "?req_id=" + requestId;

        try {
            // 发送POST请求
            ResponseEntity<String> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    requestEntity,
                    String.class
            );

            // 解析响应JSON
            return objectMapper.readValue(response.getBody(), Map.class);
        } catch (Exception e) {
            logger.error("获取音色复刻任务列表失败", e);
            return null;
        }
    }

    /**
     * 删除音色复刻任务
     * @param appId 应用ID
     * @param appKey 应用密钥
     * @param vcn 音色复刻任务ID
     * @return 删除操作响应结果
     * @throws Exception 请求异常
     */
    private Map<String, Object> deleteTask(String appId, String appKey, String vcn) throws Exception {
        String uri = "/replica/del_task";
        String requestId = generateRequestId();
        String queryParams = "req_id=" + requestId;

        // 构建请求体
        Map<String, String> body = new HashMap<>();
        body.put("vcn", vcn);

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 添加Vivo认证头
        headers.addAll(VivoAuth.generateAuthHeaders(appId, appKey, "POST", uri, queryParams));

        HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(body, headers);

        String url = "https://" + domain + uri + "?req_id=" + requestId;

        try {
            // 发送POST请求
            ResponseEntity<String> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    requestEntity,
                    String.class
            );

            // 解析响应JSON
            return objectMapper.readValue(response.getBody(), Map.class);
        } catch (Exception e) {
            logger.error("删除音色复刻任务失败", e);
            return null;
        }
    }

    /**
     * 转换音频格式
     * @param inputPath 输入音频文件路径
     * @return 转换后的音频数据
     * @throws Exception 转换异常
     */
    private byte[] convertAudioFormat(Path inputPath) throws Exception {
        AudioInputStream inputStream = AudioSystem.getAudioInputStream(inputPath.toFile());
        AudioFormat inputFormat = inputStream.getFormat();

        // 创建目标格式：24kHz采样率，16位深度，单声道
        AudioFormat targetFormat = new AudioFormat(
                AudioFormat.Encoding.PCM_SIGNED, // 编码格式
                24000,                          // 采样率
                16,                             // 位深度
                1,                              // 通道数
                2,                              // 帧大小（字节数）
                24000,                          // 帧率
                false                           // 大端序
        );

        // 如果格式已经符合要求，直接返回
        if (inputFormat.matches(targetFormat)) {
            return Files.readAllBytes(inputPath);
        }

        // 转换音频格式
        AudioInputStream convertedStream = AudioSystem.getAudioInputStream(targetFormat, inputStream);

        // 创建临时文件保存转换后的音频
        Path tempFile = Files.createTempFile("converted_", ".wav");
        try {
            // 写入WAV文件头
            AudioSystem.write(convertedStream, javax.sound.sampled.AudioFileFormat.Type.WAVE, tempFile.toFile());

            // 读取转换后的文件
            return Files.readAllBytes(tempFile);
        } finally {
            // 清理临时文件
            Files.deleteIfExists(tempFile);
            // 关闭流
            inputStream.close();
            convertedStream.close();
        }
    }

    /**
     * 检查音频文件格式
     * @param path 音频文件路径
     * @return 是否满足格式要求
     */
    private boolean checkAudioFormat(Path path) {
        try {
            // 检查文件扩展名
            if (!path.toString().toLowerCase().endsWith(".wav")) {
                logger.error("文件格式不正确，必须是WAV格式");
                return false;
            }

            // 检查文件大小
            long fileSize = Files.size(path);
            if (fileSize < 1024) { // 小于1KB
                logger.error("音频文件过小，可能质量不佳");
                return false;
            }
            if (fileSize > 10 * 1024 * 1024) { // 大于10MB
                logger.error("音频文件过大，最大支持10MB");
                return false;
            }

            // 检查音频格式
            try (AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(path.toFile())) {
                AudioFormat format = audioInputStream.getFormat();

                logger.info("当前音频格式: 采样率={}Hz, 通道数={}, 位深度={}bit, 文件大小={}MB",
                        format.getSampleRate(), format.getChannels(), format.getSampleSizeInBits(),
                        String.format("%.2f", fileSize / (1024.0 * 1024.0)));

                // 如果格式不符合要求，尝试转换
                if (format.getSampleRate() != 24000 ||
                        format.getChannels() != 1 ||
                        format.getSampleSizeInBits() != 16) {
                    logger.info("音频格式不符合要求，尝试转换...");
                    return true; // 返回true，让调用者知道可以尝试转换
                }

                logger.info("音频格式检查通过");
                return true;
            }
        } catch (Exception e) {
            logger.error("检查音频文件格式失败", e);
            return false;
        }
    }

    /**
     * 检查ASR识别结果
     * @param createResponse 创建任务响应
     * @return 是否通过检查
     */
    private boolean checkAsrResult(Map<String, Object> createResponse) {
        if (createResponse == null) {
            return false;
        }

        // 检查错误码
        int errorCode = (int) createResponse.get("error_code");
        if (errorCode != 0) {
            logger.error("创建任务失败，错误码: {}, 错误信息: {}",
                    errorCode, createResponse.get("error_msg"));
            return false;
        }

        // 检查ASR结果
        String opStr = (String) createResponse.get("op_str");
        String orgText = (String) createResponse.get("org_text");
        String asrText = (String) createResponse.get("asr_text");

        if (opStr != null && !opStr.isEmpty()) {
            logger.warn("ASR识别存在偏差，请检查录音质量");
            logger.info("原始文本: {}", orgText);
            logger.info("识别文本: {}", asrText);
            logger.info("偏差标记: {}", opStr);

            // 分析偏差类型
            int matchCount = 0;
            int errorCount = 0;
            for (char c : opStr.toCharArray()) {
                if (c == 'M') matchCount++;
                else errorCount++;
            }

            float accuracy = (float) matchCount / opStr.length() * 100;
            logger.info("识别准确率: {:.2f}%", accuracy);

            if (accuracy < 80) {
                logger.error("识别准确率过低，建议重新录制");
                return false;
            }
        }

        return true;
    }

    /**
     * 获取音色列表并打印
     * @param appId 应用ID
     * @param appKey 应用密钥
     */
    private List<Map<String, Object>> printVcnTaskList(String appId, String appKey) {

        //获取语音列表返回
        List<Map<String, Object>> rest = null;

        try {
            Map<String, Object> listResponse = getVcnTaskList(appId, appKey);
            if (listResponse == null) {
                logger.error("获取音色列表失败");
                return null;
            }

            int errorCode = (int) listResponse.get("error_code");
            if (errorCode != 0) {
                logger.error("获取音色列表失败，错误码: {}, 错误信息: {}",
                        errorCode, listResponse.get("error_msg"));
                return null;
            }

            @SuppressWarnings("unchecked")
            List<Map<String, Object>> vcnObjList = (List<Map<String, Object>>) listResponse.get("vcn_obj_list");
            if (vcnObjList == null || vcnObjList.isEmpty()) {
                logger.info("当前没有音色任务");
                return null;
            }

            logger.info("音色列表:");
            logger.info("----------------------------------------");

            rest = vcnObjList;

            for (Map<String, Object> vcnObj : vcnObjList) {
                logger.info("VCN: {}", vcnObj.get("vcn"));
                logger.info("状态: {}", getStatusDescription((int) vcnObj.get("status")));
                logger.info("创建时间: {}", vcnObj.get("create_time"));
                logger.info("更新时间: {}", vcnObj.get("update_time"));
                logger.info("完成时间: {}", vcnObj.get("complete_time"));
                logger.info("预估等待时间: {}秒", vcnObj.get("est_wait_time"));
                logger.info("进度: {}%", vcnObj.get("process"));
                logger.info("引擎ID: {}", vcnObj.get("engineid"));
                logger.info("----------------------------------------");
            }
        } catch (Exception e) {
            logger.error("获取音色列表失败", e);
        }

        return rest;
    }

    /**
     * 获取状态描述
     * @param status 状态码
     * @return 状态描述
     */
    private String getStatusDescription(int status) {
        switch (status) {
            case 1: return "等待执行";
            case 2: return "音色提取中";
            case 3: return "完成";
            case 4: return "失败";
            default: return "未知状态";
        }
    }

    /**启动1
     * 测试创建音色任务
     */
    public String testCreateVcnTask(String result,byte[] audioData) {
        try {
            
            // 创建任务
            Map<String, Object> createResponse = createVcnTask(APP_ID, APP_KEY, audioData, result);
            if (createResponse == null) {
                logger.error("创建任务失败");
                return "WJ你八嘎呀路";
            }

            // 检查ASR结果
            if (!checkAsrResult(createResponse)) {
                return "WJ你八嘎呀路";
            }

            String vcn = (String) createResponse.get("vcn");
            if (vcn == null || vcn.isEmpty()) {
                logger.error("创建任务失败，未获取到VCN");
                return "WJ你八嘎呀路";
            }

            logger.info("任务创建成功，VCN: {}", vcn);

            // 轮询任务状态
            int maxRetries = 20; // 最多等待60秒
            int retryCount = 0;
            while (retryCount < maxRetries) {
                try {
                    Thread.sleep(3000); // 每3秒查询一次状态
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }

                Map<String, Object> statusResponse = getVcnTask(APP_ID, APP_KEY, vcn);
                if (statusResponse == null) {
                    logger.error("获取任务状态失败");
                    break;
                }

                int errorCode = (int) statusResponse.get("error_code");
                if (errorCode != 0) {
                    logger.error("任务执行出错，错误码: {}, 错误信息: {}",
                            errorCode, statusResponse.get("error_msg"));
                    break;
                }

                Map<String, Object> vcnObj = (Map<String, Object>) statusResponse.get("vcn_obj");
                if (vcnObj == null) {
                    logger.error("任务状态数据异常");
                    break;
                }

                int status = (int) vcnObj.get("status");
                logger.info("当前任务状态: {}, 进度: {}%", status, vcnObj.get("process"));

                if (status >= 3) { // 状态码大于等于3表示任务完成
                    if (status == 4) {
                        logger.error("任务执行失败");
                    } else {
                        logger.info("任务完成");
                    }
                    break;
                }

                retryCount++;
                if (retryCount >= maxRetries) {
                    logger.error("任务超时，请稍后重试");
                    break;
                }
            }
        } catch (Exception e) {
            logger.error("测试创建音色任务失败", e);
        }
        return "0";
    }

    /**启动2
     * 测试获取音色列表
     */
    public List<Map<String, Object>> testGetVcnTaskList() {
        try {
            List<Map<String, Object>> rest =  printVcnTaskList(APP_ID, APP_KEY);
            return rest;
        } catch (Exception e) {
            logger.error("测试获取音色列表失败", e);
            return null;
        }
    }

    /**启动3
     * 测试删除所有音色
     */
    public void testDeleteAllVcnTasks() {
        try {
            // 获取所有音色列表
            Map<String, Object> listResponse = getVcnTaskList(APP_ID, APP_KEY);
            if (listResponse == null) {
                logger.error("获取音色列表失败");
                return;
            }

            int errorCode = (int) listResponse.get("error_code");
            if (errorCode != 0) {
                logger.error("获取音色列表失败，错误码: {}, 错误信息: {}",
                        errorCode, listResponse.get("error_msg"));
                return;
            }

            @SuppressWarnings("unchecked")
            List<Map<String, Object>> vcnObjList = (List<Map<String, Object>>) listResponse.get("vcn_obj_list");
            if (vcnObjList == null || vcnObjList.isEmpty()) {
                logger.info("当前没有音色任务");
                return;
            }

            // 删除所有音色
            for (Map<String, Object> vcnObj : vcnObjList) {
                String vcn = (String) vcnObj.get("vcn");
                logger.info("正在删除音色: {}", vcn);

                Map<String, Object> deleteResponse = deleteTask(APP_ID, APP_KEY, vcn);
                if (deleteResponse == null) {
                    logger.error("删除音色失败: {}", vcn);
                    continue;
                }

                errorCode = (int) deleteResponse.get("error_code");
                if (errorCode != 0) {
                    logger.error("删除音色失败，错误码: {}, 错误信息: {}",
                            errorCode, deleteResponse.get("error_msg"));
                } else {
                    logger.info("删除音色成功: {}", vcn);
                }
            }
        } catch (Exception e) {
            logger.error("测试删除所有音色失败", e);
        }
    }

    /**
     * 测试删除单个音色
     * @param vcn 要删除的VCN ID
     * @return 删除结果
     */
    public boolean testDeleteSingleVcnTask(String vcn) {
        try {
            Map<String, Object> deleteResponse = deleteTask(APP_ID, APP_KEY, vcn);
            if (deleteResponse == null) {
                logger.error("删除音色失败: {}", vcn);
                return false;
            }

            int errorCode = (int) deleteResponse.get("error_code");
            if (errorCode != 0) {
                logger.error("删除音色失败，错误码: {}, 错误信息: {}",
                        errorCode, deleteResponse.get("error_msg"));
                return false;
            }

            logger.info("删除音色成功: {}", vcn);
            return true;
        } catch (Exception e) {
            logger.error("删除单个音色失败", e);
            return false;
        }
    }

}
